/**
 * @file coro_runner.hpp
 * @date 2021/04/21 16:36
 *
 * @author harrybao (harrybao@123u.com)
 *
 * @brief 协程运行（暂时没用）
 *
 * @version v1.0.0
 *
 * @copyright Copyright © 2021 All Rights Reserved 上海欢乐互娱网络科技有限公司
 *
 * @par history:
 * <table>
 * <tr><th>Date                     <th>Version     <th>Author <th>Description
 * <tr><td>2021/04/21 16:36         <td>1.0.0       <td>harrybao
 * <td>创建初始版本
 * </table>
 */

// #ifndef CORO_RUNNER_HPP
// #define CORO_RUNNER_HPP

#pragma once

#include <thread>

#include "box/coro_runner.hh"
#include "coroutine/coroutine.h"
#include "detail/service_context_impl.hh"


namespace guild_service {
namespace common {

/**
 * @brief
 *
 */
class coro_runner {
 public:
  using coro_type = kratos::service::CoroRunner;
  using coro_ptr_type = std::unique_ptr<kratos::service::CoroRunner>;
  using coro_function_type = kratos::service::CoFunction;
  using coro_id_type = kratos::service::COID;

  coro_runner() : m_user_count(0), m_started(false), m_coro_ptr(nullptr) {}

  ~coro_runner() {
    if (m_started) {
      m_started = false;
    }
    if (m_thread.joinable()) {
      m_thread.join();
    }
  }

  /**
   * @brief
   *
   * @param context
   * @return true
   * @return false
   */
  bool start(kratos::service::ServiceContext* context) {
    m_user_count++;
    if (m_started) {
      return true;
    }
    // coro_start()
    auto* context_impl =
        static_cast<kratos::service::ServiceContextImpl*>(context);
    m_coro_ptr = std::move(context_impl->new_coro_runner());

    m_started = true;
    m_thread = std::thread(&coro_runner::run, this);

    return true;
  }

  /**
   * @brief
   *
   * @return true
   * @return false
   */
  bool stop() {
    m_user_count--;
    if (m_user_count == 0) {
      m_started = false;
    }
    return true;
  }

  /**
   * @brief
   *
   * @return true
   * @return false
   */
  inline bool started() const { return m_started; }

  /**
   * @brief
   *
   * @param func
   * @return coro_id_type
   */
  coro_id_type start_co(coro_function_type func) {
    return m_coro_ptr->start_co(func);
  }

  /**
   * @brief
   *
   */
  void run() {
    while (m_started) {
      // coro_sched();
      // m_coro_ptr->co
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
  }

 private:
  ///
  int m_user_count;
  ///
  bool m_started;
  ///
  coro_ptr_type m_coro_ptr;
  ///
  std::thread m_thread;
};
}  // namespace common

#define CoroSingleton (common::singleton<common::coro_runner>::instance())

inline static void coroutine_destroy() {
  singleton<common::coro_runner>::destroy();
}

inline static bool coroutine_start(kratos::service::ServiceContext* context) {
  return CoroSingleton->start(context);
}

inline static bool coroutine_stop() {
  if (!CoroSingleton->stop()) {
    return false;
  }
  if (!CoroSingleton->started()) {
    coroutine_destroy();
  }
  return true;
}

}  // namespace guild_service

// #endif // CORO_RUNNER_HPP